package com.ansion.utils;

import android.content.Context;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;

import androidx.annotation.NonNull;


import com.ansion.utils.thread.NamedThreadFactory;
import com.ansion.utils.thread.SafeRunnable;
import com.ansion.utils.thread.ThreadPool;

import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * 使用线程池执行异步任务，避免过多的线程创建
 * 即时任务/计算任务/轻量级任务请调用：runTask
 * IO任务/网络请求/文件存取请调用：runIOTask
 * 数据库操作请调用：runDbTask
 * 后台顺序执行任务请调用：runSingleTask或者runOnWorker
 * 如果需要直接运行thread请调用：runThread
 * 业务层使用时候请注意，切换到UI线程执行任务，请调用runUi或者runUiSafely。如果需要检查生命周期请调用runUiSafely，不需要则调用runUi。
 * 全局统一使用一个定时器，大家每个timer和HandlerThread底层都有一个死循环的Thread，后台过多的线程开销会造成功能异常
 */
public final class ThreadUtil {

    private static Executor singleExecutor;
    private static volatile Handler rpcHandler;

    //room数据库线程
    private static volatile Handler roomDBHandler;


    private ThreadUtil() {
    }


    /**
     * 方便统计有哪些地方用了线程
     *
     * @param runnable
     * @param threadName
     */
    public static void runSmallTask(Runnable runnable, String threadName) {
        ThreadPool.runCalculate(new Thread(runnable, threadName));
    }

    public static void runDbTask(Runnable runnable) {
        ThreadPool.runDatabase(runnable);
    }

    public static void runDbTask(Runnable runnable, String threadName) {
        ThreadPool.runDatabase(new Thread(runnable, threadName));
    }


    public static void runDbDelay(long delayMs, Runnable runnable) {
        ThreadPool.runDbDelayed(delayMs, runnable);
    }

    public static void runIODelay(long delayMs, Runnable runnable) {
        ThreadPool.runIoDelayed(delayMs, runnable);
    }

    public static void removeIo(Runnable runnable) {
        ThreadPool.removeIo(runnable);
    }

    public static void runSmallTaskDelay(long delayMs, Runnable runnable) {
        ThreadPool.runCalculatorDelayed(delayMs, runnable);
    }


    public static void runSingleTask(Runnable runnable) {
        if (singleExecutor == null)
            singleExecutor = Executors.newSingleThreadExecutor(new NamedThreadFactory("SingleTask"));
        singleExecutor.execute(runnable);
    }

    public static void runSmallTask(Runnable runnable) {
        ThreadPool.runCalculate(runnable);
    }

    public static void runIOTask(Runnable runnable) {
        ThreadPool.runIO(runnable);
    }

    public static void runIOTask(Runnable runnable, String name) {
        ThreadPool.runIO(new Thread(runnable, name));
    }

    public static void runUiSafely(@NonNull Context context, @NonNull Runnable task) {
        SafeRunnable safeTask = new SafeRunnable(context) {
            @Override
            protected void runSafely() {
                task.run();
            }
        };
        if (isUIThread()) {
            safeTask.run();
        } else {
            ThreadPool.runMain(safeTask);
        }

    }

    public static void postOnUiSafely(@NonNull Context context, @NonNull Runnable task) {
        SafeRunnable safeTask = new SafeRunnable(context) {
            @Override
            protected void runSafely() {
                task.run();
            }
        };
        ThreadPool.getUIHandler().post(safeTask);
    }


    public static void runUiSafelyDelayed(@NonNull Context context, long delayMs,
                                          @NonNull Runnable task) {
        if (delayMs > 0) {
            ThreadPool.runUiDelayed(context, delayMs, task);
        } else {
            runUiSafely(context, task);
        }
    }

    public static void runUi(@NonNull Runnable task) {
        if (isUIThread()) {
            task.run();
        } else {
            ThreadPool.runMain(task);
        }
    }

    public static void runUiImmediately(@NonNull Runnable task) {
        if (isUIThread()) {
            task.run();
        } else {
            ThreadPool.runUiImmediately(task);
        }
    }

    public static void runUiDelay(@NonNull Runnable task, int delayMs) {
        ThreadPool.runMainDelay(task, delayMs);
    }

    public static boolean isUIThread() {
        return Thread.currentThread() == Looper.getMainLooper().getThread();
    }

    /***
     *
     * workerHandler执行任务不要超过5秒钟，如果需要长时间独占，则需要自己新建
     */
    public static void runOnWorker(Runnable r) {
        ThreadPool.runOnWorker(r);
    }



    public static void runRoomDBWorker(Runnable r) {
        getRoomDBHandler().post(r);
    }


    @Deprecated
    public static void runThread(Runnable r, String threadName) {
        ThreadPool.runThread(r, threadName);
    }

    /***
     *
     * workerHandler执行任务不要超过5秒钟，如果需要长时间独占，则需要自己新建
     */
    public static void runOnWorkerDelay(Runnable r, long delayMs) {
        ThreadPool.postOnWorkerDelayed(r, delayMs);
    }

    /***
     *
     * workerHandler执行任务不要超过5秒钟，如果需要长时间独占，则需要自己新建
     */
    public static Handler getWorkerHandler() {
        return ThreadPool.getWorkerHandler();
    }


    /***
     * 定时执行db任务
     * @param task
     * @param delayMs
     * @param periodMs
     */
    public static void scheduleDbTask(Runnable task, long delayMs, long periodMs) {
        ThreadPool.scheduleDbTask(task, delayMs, periodMs);
    }


    /***
     * 定时执行db任务
     * @param task
     * @param delayMs
     * @param periodMs
     */
    public static void scheduleIoTask(Runnable task, long delayMs, long periodMs) {
        ThreadPool.scheduleIoTask(task, delayMs, periodMs);
    }


    /***
     * 定时执行db任务
     * @param task
     * @param delayMs
     * @param periodMs
     */
    public static void scheduleSmallTask(Runnable task, long delayMs, long periodMs) {
        ThreadPool.scheduleCalculateTask(task, delayMs, periodMs);
    }

    public static Handler getRpcCallBackHandler(boolean uiCallBack) {
        if (uiCallBack)
            return ThreadPool.getUIHandler();
        return getRpcHandler();
    }

    public static Handler getUIHandler() {
        return ThreadPool.getUIHandler();
    }

    private static Handler getRpcHandler() {
        if (rpcHandler == null) {
            synchronized (ThreadUtil.class) {
                if (rpcHandler == null) {
                    HandlerThread rpcThread = new HandlerThread("RpcHandler");
                    rpcThread.start();
                    rpcHandler = new Handler(rpcThread.getLooper());
                }
            }
        }
        return rpcHandler;
    }


    public static Handler getRoomDBHandler() {
        if (roomDBHandler == null) {
            synchronized (ThreadUtil.class) {
                if (roomDBHandler == null) {
                    HandlerThread handlerThread = new HandlerThread("RoomDBHandler");
                    handlerThread.start();
                    roomDBHandler = new Handler(handlerThread.getLooper());
                }
            }
        }
        return roomDBHandler;
    }

    public static Future<?> submitIO(Runnable task) {
        return ThreadPool.submitIO(task);
    }

    public static Future<?> submitDB(Runnable task) {
        return ThreadPool.submitDB(task);
    }

    public static Future<?> submitCalculator(Runnable task) {
        return ThreadPool.submitCalculator(task);
    }

}
